package vboot.core.module.mon.server.snmp;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.*;
import org.snmp4j.mp.MessageProcessingModel;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.PDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableUtils;
import vboot.core.common.utils.ruoyi.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.List;

@Slf4j
public class SnmpDisk {

    public static void main(String[] args) {
        try {
            String ip = "localhost";
            String community = "public";
            String system = "windows";
            JSONArray array = new JSONArray();
            JSONObject obj = new JSONObject();
            obj.put("name", "D:");
            array.add(obj);
            MemoryData memoryData = collectDisk(ip, community, array, system);
            System.out.println(memoryData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取磁盘相关信息
    public static MemoryData collectDisk(String ip, String community, JSONArray array, String system) throws Exception {
        //system: windows, linux
        String name; //磁盘名称
        BigDecimal totalSize = new BigDecimal("0");
        BigDecimal usedSize = new BigDecimal("0");
        BigDecimal unit1024 = new BigDecimal("1024");
        String binaryVal;
        TransportMapping transport = null;
        Snmp snmp = null;
        CommunityTarget target;
        String DISK_OID = "1.3.6.1.2.1.25.2.1.4";
        String[] oids = {
                "1.3.6.1.2.1.25.2.3.1.2", // type 存储单元类型
                "1.3.6.1.2.1.25.2.3.1.3", // descr
                "1.3.6.1.2.1.25.2.3.1.4", // unit 存储单元大小
                "1.3.6.1.2.1.25.2.3.1.5", // size 总存储单元数
                "1.3.6.1.2.1.25.2.3.1.6"  // used 使用存储单元数;
        };
        try {
            target = new CommunityTarget();
            target.setCommunity(new OctetString(community)); //设置snmp共同体(社区名称)
            target.setRetries(2); //设置超时重试次数
            target.setAddress(GenericAddress.parse("udp:"+ ip +"/161")); //设定主机的地址
            target.setTimeout(1000*5); //设置超时的时间
            target.setVersion(SnmpConstants.version2c); //设置使用的snmp版本

            transport = new DefaultUdpTransportMapping(); //设定采取的协议
            snmp = new Snmp(transport); //创建SNMP对象
            snmp.listen();// 监听消息

            TableUtils tableUtils = new TableUtils(snmp, new PDUFactory() {
                @Override
                public PDU createPDU(Target arg0) {
                    PDU request = new PDU();
                    request.setType(PDU.GET);
                    return request;
                }

                @Override
                public PDU createPDU(MessageProcessingModel messageProcessingModel) {
                    // TODO Auto-generated method stub
                    return null;
                }
            });

            OID[] columns = new OID[oids.length];
            for (int i = 0; i < oids.length; i++) {
                columns[i] = new OID(oids[i]);
            }

            @SuppressWarnings("unchecked")
            List<TableEvent> list = tableUtils.getTable(target, columns, null, null);
            if (list.size() == 1 && list.get(0).getColumns() == null) {
                log.info(ip + "：未取到数据");
                System.out.println(JSONArray.toJSON(list).toString());
            } else {
                for (TableEvent event : list) {
                    VariableBinding[] values = event.getColumns();
                    if (values == null || !DISK_OID.equals(values[0].getVariable().toString())) {
                        continue;
                    }
                    // unit 存储单元大小
                    String unit = StringUtils.changeValBinary(values[2].getVariable().toString());
                    // size 总存储单元数
                    String totalSizeCell = StringUtils.changeValBinary(values[3].getVariable().toString());
                    // used 使用存储单元数
                    String usedSizeCell = StringUtils.changeValBinary(values[4].getVariable().toString());

                    //磁盘名称
                    name = getChinese(values[1].getVariable().toString());
                    if(name==null || "".equals(name)) {
                        name = values[1].getVariable().toString();
                    }
                    //System.out.println(name);
                    boolean check = checkDiskName(array, name, system); //是否统计
                    if(check) {
                        BigDecimal unitBig = new BigDecimal(unit +"");
                        totalSize = totalSize.add(
                                new BigDecimal(totalSizeCell +"").multiply(unitBig)
                                        .divide(unit1024, 2, BigDecimal.ROUND_HALF_UP)
                                        .divide(unit1024, 2, BigDecimal.ROUND_HALF_UP)
                                        .divide(unit1024, 2, BigDecimal.ROUND_HALF_UP));
                        usedSize = usedSize.add(
                                new BigDecimal(usedSizeCell +"").multiply(unitBig)
                                        .divide(unit1024, 2, BigDecimal.ROUND_HALF_UP)
                                        .divide(unit1024, 2, BigDecimal.ROUND_HALF_UP)
                                        .divide(unit1024, 2, BigDecimal.ROUND_HALF_UP));
                    }


                    //System.out.println("totalSize:" + (long)totalSizeCell*unit/(1024*1024*1024)+"G");
                    //System.out.println("usedSize" + (long)usedSizeCell*unit/(1024*1024*1024)+"G");
                    //System.out.println("%%:" + (long)usedSizeCell*100/totalSizeCell+"%");
                    // System.out.println(getChinese(values[1].getVariable().toString())+"
                    // 磁盘大小："+(long)totalSize*unit/(1024*1024*1024)+"G
                    // 磁盘使用率为："+(long)usedSize*100/totalSize+"%");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            log.error("未能连接到snmp服务：" + ip);
        } finally {
            try {
                if (transport != null)
                    transport.close();
                if (snmp != null)
                    snmp.close();
            } catch (IOException e) {
                e.printStackTrace();
                log.error(e.getMessage());
            }
        }

        DecimalFormat setDouble_1 = new DecimalFormat("0.0"); //保留1位小数
        MemoryData memoryData = new MemoryData();
        memoryData.setTotalSize(setDouble_1.format(totalSize));
        memoryData.setUserdSize(setDouble_1.format(usedSize));
        memoryData.setAddress(ip);
        memoryData.setUnit("G");

        //System.out.println("totalSize:" + setDouble_1.format(totalSize) + "G");
        //System.out.println("usedSize:" + setDouble_1.format(usedSize) + "G");
        //System.out.println("usedSize" + (long)usedSize*100/totalSize+"%");

        return memoryData;
    }

    /**
     * 判断是否需要统计
     * @param array
     * @param name
     * @param system
     * @return
     */
    public static boolean checkDiskName(JSONArray array, String name, String system) {
        boolean check = false; //是否统计
        //不维护则取全部
        if(array.size() == 0) {
            return true;
        }
        JSONObject obj = new JSONObject();
        String setName;
        for(int i=0; i<array.size(); i++) {
            obj = array.getJSONObject(i);
            setName = obj.getString("name");
            if("windows".equals(system)) {
                if(name.contains(setName)) {
                    check = true;
                }
            }
            if("linux".equals(system)) {
                if(name.equals(setName)) {
                    check = true;
                }
            }
        }
        return check;
    }

    /**
     * 获取磁盘的中文名字
     * 解决snmp4j中文乱码问题
     */
    public static String getChinese(String octetString){
        int COLON_SIZE = 0;
        if (octetString == null || "".equals(octetString) || "null".equalsIgnoreCase(octetString))
            return "";
        try {
            String[] temps = octetString.split(":");
            if (temps.length < COLON_SIZE)
                return octetString;
            byte[] bs = new byte[temps.length];
            for (int i = 0; i < temps.length; i++)
                bs[i] = (byte) Integer.parseInt(temps[i], 16);
            return new String(bs, "GB2312");
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 将16进制的时间转换成标准的时间格式
     */
    private static String hexToDateTime(String hexString) {
        if (hexString == null || "".equals(hexString))
            return "";
        String dateTime = "";
        try {
            byte[] values = OctetString.fromHexString(hexString).getValue();
            int year, month, day, hour, minute;

            year = values[0] * 256 + 256 + values[1];
            month = values[2];
            day = values[3];
            hour = values[4];
            minute = values[5];

            char format_str[] = new char[22];
            int index = 3;
            int temp = year;
            for (; index >= 0; index--) {
                format_str[index] = (char) (48 + (temp - temp / 10 * 10));
                temp /= 10;
            }
            format_str[4] = '-';
            index = 6;
            temp = month;
            for (; index >= 5; index--) {
                format_str[index] = (char) (48 + (temp - temp / 10 * 10));
                temp /= 10;
            }
            format_str[7] = '-';
            index = 9;
            temp = day;
            for (; index >= 8; index--) {
                format_str[index] = (char) (48 + (temp - temp / 10 * 10));
                temp /= 10;
            }
            format_str[10] = ' ';
            index = 12;
            temp = hour;
            for (; index >= 11; index--) {
                format_str[index] = (char) (48 + (temp - temp / 10 * 10));
                temp /= 10;
            }
            format_str[13] = ':';
            index = 15;
            temp = minute;
            for (; index >= 14; index--) {
                format_str[index] = (char) (48 + (temp - temp / 10 * 10));
                temp /= 10;
            }
            dateTime = new String(format_str, 0, format_str.length).substring(0, 16);
        } catch (Exception e) {
            // LogFactory.getLog(getClass()).error(e);
        }
        return dateTime;
    }
}
